package ThreadPoolnio1;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;

public class NIOServer extends Thread {
    static final int TIMEOUT = 3000;
    static final int PORT = 9999;
    static final int BUF_SIZE = 1024;

    public static void main(String[] args) {
        selector();
    }

    @Override
    public void run() {
        selector();
    }

    public static void selector(){
        Selector selector = null;
        ServerSocketChannel ssc = null;
        try {
            //第一步，创建Selector
            selector = Selector.open();
            //第二步，创建ServerSocketChannel 绑定监听端口   基于通道的tcp服务端
            ssc = ServerSocketChannel.open();
            ssc.socket().bind(new InetSocketAddress(PORT));
            //第三步，将channel 设置为阻塞模式
            ssc.configureBlocking(false);
            //第四步，将channel 注册到Selector上，监听和连接事件  *****
            ssc.register(selector , SelectionKey.OP_ACCEPT);
            //第五步，循环调用Selector的select方法，检测监听情况
            while (true){
                if (selector.select(TIMEOUT) == 0){
                    //Syste,.out.println("===等待连接===");
                    continue;
                }
                //第六步，调出selectedKeys方法获取就绪channel集合·
                Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
                while (iterator.hasNext()) {
                    SelectionKey key = iterator.next();
                    //第七步，判断就绪事实种类，调用业务处理方法      key就相当于客户端
                    if (key.isValid() && key.isAcceptable()) {
                        handleAccept(key);
                    }
                    if (key.isValid() && key.isConnectable()) {
                        System.out.println("isConnectable = true");
                    }
                    if (key.isValid() && key.isReadable()) {
                        handleRead(key);
                    }
                    if (key.isValid() && key.isWritable()) {
                        handleWrite(key);
                    }
                    iterator.remove();
                }
            }
        } catch (ClosedChannelException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        finally {
            try {
                if(selector != null){
                    selector.close();
                }
                if(ssc != null){
                    ssc.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static void handleAccept(SelectionKey key) throws IOException{
        ServerSocketChannel ssChannel = (ServerSocketChannel)key.channel();
        SocketChannel sc = ssChannel.accept();
        sc.configureBlocking(false);
        sc.register(key.selector() , SelectionKey.OP_READ , ByteBuffer.allocateDirect(BUF_SIZE));
        System.out.println("===========" + sc.getRemoteAddress()+ "连接==========");
    }
    public static void handleRead(SelectionKey key) throws IOException{
        //拿到Selector 中的 channel；
        SocketChannel sc = (SocketChannel)key.channel();
        System.out.println("===========" + sc.getRemoteAddress()+ "消息==========");
        ByteBuffer buf = (ByteBuffer)key.attachment();
        long byteRead = sc.read(buf);
        while(byteRead > 0){
            buf.flip();
            //为了处理中文做了特殊处理
            byte[] bytes = new byte[BUF_SIZE];
            int i = 0;
            while(buf.hasRemaining()){
                bytes[i] = buf.get();
                i++;
            }
         System.out.println(new String(bytes,"GBK"));
            buf.clear();
            byteRead = sc.read(buf);
        }
        if(byteRead == -1){
            sc.close();
        }
    }
    public static void handleWrite(SelectionKey key) throws IOException{
        ByteBuffer buf = (ByteBuffer)key.attachment();
        buf.flip();
        SocketChannel sc = (SocketChannel) key.channel();
        while (buf.hasRemaining()){
            sc.write(buf);
        }
        buf.compact();
    }
}
